/**
 * DList represents a double ended list for character strings.
 * In addition, DList provides for an iterator called DListIterator.
 * As you can see in the code below, the class DListTest is declared
 * as friend, because you can test more in deep. As example it is
 * important to check the links of the DListElements, which is not
 * possible over the public interfaces of DList.
 *
 * Note: You can check out all sources as eclipse cpp project
 *       over http://stuff-from-hell.googlecode.com/svn/trunk/cpp_ex
 *
 * @author  Benjamin Friedrich (3453464)
 * 			benjamin_friedrich@gmx.de
 * @version 1.0  17.01.2009
 */
#ifndef DLIST_HPP_
#define DLIST_HPP_

#include <string>

/*
 * The struct DListElement serves DList as wrapper for
 * one character string and links to the previous and the next
 * DListElement.
 */
struct DListElement
{
	const char   *charString; // actual data
	DListElement *previous ;  // link to previous list element
	DListElement *next;       // link to next list element
};

class DList
{
	//-- friends:
	friend class DListTest;      // Serves for deep testing of DList
	friend class DlistIterator;  // Iterator of DList

	/**
	 * Compares 2 DList lists
	 *
	 * @param list1
	 * @param list2
	 *
	 * @return true if both lists are equal, false otherwíse
	 */
	friend bool  operator==(const DList &list1, const DList &list2);

	/**
	 * Decides whether 2 DList lists are not equal. operator!=()
	 * uses the negiotation of the return value of operator==().
	 *
	 * @param list1
	 * @param list2
	 *
	 * @return  true if both lists are not equal, false otherwise
	 */
	friend inline bool operator!=(const DList &list1, const DList &list2)
	{ return !(list1 == list2); };

	/**
	 * Concatenates two lists to one new list.
	 *
	 * @param the head list
	 * @param the tail list
	 *
	 * @return list which contains both lists.
	 */
	friend DList operator+ (const DList &listHead, const DList &listTail);

private:
	unsigned int numberOfElements; // number of elements in DList
	DListElement *first;           // first element of DList
	DListElement *last;            // last element of DList

	static const char *TO_STRING_SEPARATOR; // separator for the toString() output

	/**
	 * Helper method to imports an other list in this list.
	 *
	 * @param  list to import
	 */
	void importList(const DList &list);

	/**
	 * Helper method to initialize DList.
	 */
	void init();
public:

	/**
	 * Standard constructor of DList
	 */
	inline DList()
	{ this->init(); };

	/**
	 * Constructor of DList, which constructs the list with
	 * an array of character strings.
	 *
	 * @param  array of character strings
	 * @param  number of character strings in the given array
	 */
	DList(const char **charStrings, const int &numberOfStrings);

	/**
	 * Copy constructor of DList
	 *
	 * @param  source list to copy for
	 */
	DList(const DList  &list);

	/**
	 * Deconstructor of DList
	 */
	inline ~DList()
	{ this->clear(); }

	/**
	 * Pushes the given character string at the end of the list
	 *
	 * @param  character string to push for
	 * @return true if pushBack() was successful, false otherwise
	 */
	inline bool pushBack(const char *charString)
	{ return this->insert(this->numberOfElements, charString); };

	/**
	 * Pushes a character string at the begin of the list
	 *
	 * @param  character string to push for
	 * @return true if pushFront() was successful, false otherwise
	 */
	inline bool pushFront(const char *charString)
	{ return this->insert(0, charString); };

	/**
	 * Pops the last element of the list and returns its character string.
	 *
	 * @return character string of the removed element or NULL if popBack()
	 *         was not successful
	 */
	inline const char* popBack()
	{ return this->remove(this->numberOfElements - 1); };

	/**
	 * Pops the first element of the list and returns its character string.
	 *
	 * @return character string of the removed element or NULL if popFront()
	 *         was not successful
	 */
    inline const char* popFront()
    { return this->remove(0); };

    /**
     * Inserts the given character string at the given position.
     *
     * @param  position (starts at 0)
     * @param  character string to insert for
     *
     * @return true if inserts was successful, false otherwise
     *         (e.g. when: list.size() == 2; list.insert(10, "no chance!"); )
     */
	bool insert(const unsigned int &position, const char *charString);

	/**
	 * Removes the element at the given position and returns its character string.
	 *
	 * @param  position (starts at 0)
	 *
	 * @return character string of the removed element or NULL if remove()
	 *         was not successful
	 */
	const char* remove(const unsigned int &position);

	/**
	 * Clears the list.
	 */
	void clear();

	/**
	 * Returns the number of elements in the list.
	 *
	 * @return number of elements in the list
	 */
	inline unsigned int size() const
	{ return this->numberOfElements; };

	/**
	 * Assigns an other list to this list. This means that this list
	 * becomes a equivalent list of the other list.
	 *
	 * @param  the other list
	 * @return reference to *this
	 */
	DList& operator=(const DList &list);

	/**
	 * Concatenates an other list with this list.
	 *
	 * @param  the other list
	 * @return reference to *this
	 */
	DList& operator+=(const DList &list);

	/**
	 * This operator returns the character string at the given index
	 * or NULL, [] was not sucessful
	 *
	 * @param  list index (starts at 0)
	 * @return character string at the given index or NULL if [] was not
	 *         successful
	 */
	const char *operator[](const unsigned int &index) const;

	/**
	 * Creates the string representation of this list
	 *
	 * @return string representation
	 */
	const std::string toString() const;

    //----------------------------------------------------------------------

	/**
	 * DListIterator is the iteratir of DList
	 *
	 * @author  Benjamin Friedrich (3453464)
	 * 			benjamin_friedrich@gmx.de
	 * @version 1.0  17.01.2009
	 */
	class DListIterator
	{
	   //-- friends:
	   friend class DListTest;

	   /**
	    * Compares 2 iterators.
	    *
	    * @param iterator1
	    * @param iterator2
	    *
	    * @return true if both are equal, false otherwise
	    */
	   friend bool operator==(const DList::DListIterator &iterator1,
			                  const DList::DListIterator &iterator2);

	   /**
	    * Tests whether the two given iterators are not equal
	    *
	    * @param iterator1
	    * @param iteraror2
	    *
	    * @return  true if both are not equal, false otherwise
	    */
	   inline friend bool operator!=(const DList::DListIterator &iterator1,
			                         const DList::DListIterator &iterator2)
	   { return ! (iterator1 == iterator2); };


	private:
		DListElement *current; // DListElement of this iterator

		static const DListElement THE_END;

	public:

		/**
		 * Constructor of DListIterator
		 *
		 * @param DListElement for this iterator or nothing
		 */
		inline DListIterator(DListElement *current = NULL)
		{ this->current = current; };

		static const DListIterator PSEUDO_LAST;

		/**
		 * Returns an iterator with the current element of this iterator,
		 * goes to the next DListElement of the current element.
		 *
		 * @return  iterator with the old current element of this iterator
		 */
		DListIterator operator++(int);

		/**
		 * Returns the character string of the current list position of this
		 * iterator.
		 *
		 * @return character string
		 */
		inline const char* operator*()
		{ return this->current != NULL ? this->current->charString : NULL; };
	};

	//-----------------------------------------------------------------------------

	//-- iterator-methods

	/**
	 * Returns an iterator of the first list position
	 *
	 * @return iterator
	 */
   inline DListIterator begin() const
   { return DListIterator(this->first); }

   /**
    * Returns an iterator of the last list position
    *
    * @return iterator
    */
   inline DListIterator end  () const
   { return DListIterator::PSEUDO_LAST; }
};
#endif /* DLIST_HPP_ */
